/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package edu.webbapps.cormac_susilo.core;

import edu.webbapps.cormac_susilo.bootstrap.BootWrap;
import edu.webbapps.cormac_susilo.fit.CormacFitDecoder;
import edu.webbapps.cormac_susilo.wrappers.FrameWrapper;
import edu.webbapps.cormac_susilo.wrappers.RunWrapper;
import edu.webbapps.cormac_susilo.wrappers.UserWrapper;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.enterprise.context.SessionScoped;
import javax.inject.Inject;
import javax.persistence.RollbackException;

/**
 * A bean to manager all Interactions with the user data.
 * 
 * @author tor
 */
@SessionScoped
public class UserManagerBean implements IUserModel {

    @Inject
    private BootWrap cormac;

    @Override
    public List<FrameWrapper> getFrames(long run_id) {
        List<Frame> frames = cormac.getFrameRegistry().getFrames(run_id);
        if (frames.isEmpty())
            throw new NoSuchElementException();

        List<FrameWrapper> frames_w = new ArrayList<FrameWrapper>(frames.size());
        for (Frame f : frames) {
            frames_w.add(new FrameWrapper(f));
        }
        return frames_w;
    }

    @Override
    public List<String> getTracks(long user_id) {
        List<String> tracks = cormac.getRunRegistry().getTrackNamesByUserId(user_id);
        if (tracks.isEmpty())
            throw new NoSuchElementException();
        
        return tracks;
    }

    @Override
    public RunWrapper getRun(long run_id) {
        Run r = cormac.getRunRegistry().find(run_id);
        if (r == null)
            throw new NoSuchElementException("Run id not found");
        
        return new RunWrapper(r);
    }

    @Override
    public List<RunWrapper> getRuns(long user_id) {
        List<Run> runs = cormac.getRunRegistry().getByUserId(user_id);
        if (runs.isEmpty())
            throw new NoSuchElementException("Run id not found");
        
        List<RunWrapper> runs_w = new ArrayList<RunWrapper>(runs.size());
        for (Run r : runs) {
            runs_w.add(new RunWrapper(r));
        }

        return runs_w;
    }

    @Override
    public List<RunWrapper> getRuns(long user_id, String trackname) {
        List<Run> runs = cormac.getRunRegistry().getByUserAndName(user_id, trackname);
        if (runs.isEmpty())
            throw new NoSuchElementException("Run not found");
        
        List<RunWrapper> runs_w = new ArrayList<RunWrapper>(runs.size());
        for (Run r : runs) {
            runs_w.add(new RunWrapper(r));
        }

        return runs_w;
    }

    @Override
    public RunWrapper renameRun(long run_id, String new_trackname) throws NoSuchElementException, RollbackException {
        
        Run run = cormac.getRunRegistry().find(run_id);
        try {

            run.setTrackname(new_trackname);
            cormac.getRunRegistry().update(run);
            run = cormac.getRunRegistry().find(run_id);
            return new RunWrapper(run);
            
        } catch (RollbackException e) {
            Logger.getLogger(UserManagerBean.class.getName()).log(Level.INFO, e.getMessage());
            throw e;
        } catch (NullPointerException e) {
            throw new NoSuchElementException("Run id not found");
        }
    }

    @Override
    public List<RunWrapper> renameRuns(long user_id, String trackname, String new_trackname) {
        try {
            cormac.getRunRegistry().changeTrackNames(user_id, trackname, new_trackname);
            return this.getRuns(user_id, new_trackname);
            
        } catch (RollbackException e) {
            Logger.getLogger(UserManagerBean.class.getName()).log(Level.INFO, e.getMessage());
            throw e;
        }
    }

    @Override
    public boolean deleteRun(long run_id) throws NoSuchElementException, RollbackException {
        boolean success = false;
        try {
            // TODO this hould be one transaction, not two since we update both 
            // a user and a Run and it may fail at any time.
            
            // This also deletes frames
            Run run = cormac.getRunRegistry().find(run_id);
            double d = run.getDistance();
            double t = run.getTotalTime();
            
            cormac.getRunRegistry().remove(run_id);
            
            //TODO Update user object
            User u = run.getUser();
            u.setTotal_distance(u.getTotal_distance() - d);
            u.setTotal_time(u.getTotal_time() - t);
            cormac.getUserRegistry().update(u);
            
            success = true;

        } catch (RollbackException e) {
            Logger.getLogger(UserManagerBean.class.getName()).log(Level.INFO, e.getMessage());
            throw e;
        } catch (NullPointerException e) {
            throw new NoSuchElementException("Run id not found");
        }
        return success;
    }

    @Override
    public List<UserWrapper> getUsers() {
        List<User> users = cormac.getUserRegistry().getAll();
        List<UserWrapper> users_w = new ArrayList<UserWrapper>(users.size());
        for (User u : users) {
            users_w.add(new UserWrapper(u));
        }
        return users_w;
    }
    @Override
    public UserWrapper getUser(long user_id) throws NoSuchElementException {
        User u = cormac.getUserRegistry().find(user_id);
        if (u == null) {
            throw new NoSuchElementException("User id not found");
        }
        
        return new UserWrapper(u);
    }

    @Override
    public UserWrapper createUser(
            String username,
            String password,
            String avatar,
            String givenname,
            String familyname,
            String email) throws RollbackException {

        User u = new User(email, password, avatar, givenname, familyname, email);
        
        try {
            cormac.getUserRegistry().add(u);
            u = cormac.getUserRegistry().find(u.getId());
            return new UserWrapper(u);
            
        } catch (RollbackException e) {
            throw e;
        }
    }

    @Override
    public UserWrapper updateUser(
            long user_id,
            String username,
            String password,
            String avatar,
            String Givenname,
            String Familyname,
            String email) throws NoSuchElementException, RollbackException {

        User u = cormac.getUserRegistry().find(user_id);
        try {
            u.setName(username); // uniqueness constraint
            u.setPassword(password);
            u.setAvatar(avatar);
            u.setGivenname(Givenname);
            u.setFamilyname(Familyname);
            u.setEmail(email);

            cormac.getUserRegistry().update(u);
            u = cormac.getUserRegistry().find(user_id);

        } catch (RollbackException e) {
            throw e;
        } catch (NullPointerException e) {
            throw new NoSuchElementException("User id not found");
        }

        return new UserWrapper(u);
    }

    @Override
    public boolean deleteUser(long user_id) throws NoSuchElementException, RollbackException {
        boolean success = false;

        try {
            User u = cormac.getUserRegistry().find(user_id);
            cormac.getUserRegistry().remove(u.getId());
            success = true;
        } catch (RollbackException e) {
            throw e;
        } catch (NullPointerException e) {
            throw new NoSuchElementException("User id not found");
        }

        return success;
    }

    @Override
    public UserWrapper uploadFile(long user_id, InputStream in, String trackname) {
        User u = cormac.getUserRegistry().find(user_id);
        if (u == null)
            throw new NoSuchElementException("User not found");
        
        CormacFitDecoder.loadDataIntoUser(u, in, trackname, true);
        cormac.getUserRegistry().update(u);
        u = cormac.getUserRegistry().find(user_id);
        return new UserWrapper(u);
    }

    @Override
    public UserWrapper getUser(String username) throws NoSuchElementException {
        User u = cormac.getUserRegistry().findByName(username);
        if (u == null)
            throw new NoSuchElementException("User not found " + username);
        return new UserWrapper(u);
    }
}
